/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * 
 */
package dgbgui.actions;

import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.EnumMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.KeyStroke;

/**
 * Singleton class for all the available actions
 * @author bjnortier
 *
 */
public class ActionRepository  {
	
	public static enum ActionName {
        // FILE GROUP
        FILE_NEW,
        FILE_OPEN,
        FILE_SAVE,
        FILE_SAVE_AS,
	    // EDIT GROUP
        EDIT_UNDO,
        EDIT_REDO,
        EDIT_DELETE,
        EDIT_RENAME,
        EDIT_MODIFY,
        EDIT_CUT,
        EDIT_COPY,
        EDIT_PASTE,
        // QUERY_GROUP
        QUERY_ADD_TYPES,
		QUERY_CREATE_SET,
        QUERY_EXECUTE,
        QUERY_CREATE_CUSTOM,
        QUERY_CREATE_FROM_RESULT,
        QUERY_CREATE_NEIGHBOURHOOD,
        QUERY_CREATE_CLOSURE,
		// BOOLEAN GROUP
		BOOLEAN_INTERSECT,
		BOOLEAN_UNION,
		BOOLEAN_NOT,
        BOOLEAN_XOR,
        // APPLICATION GROUP
        DGB_SETTINGS,
        DGB_GET_IOR_VIA_HTTP,
        // MODEL_DRIVEN
        MODEL_SET_TARGET,
        // Perspectives Group
        PERSPECTIVE_DEFAULT,
        PERSPECTIVE_MODEL,

	}
	
	/**
	 * The properties for each action, such as caption, description, icon and shortcut
	 */
	public class ActionProperties {
		
        public ActionProperties(String caption, String description, KeyStroke keyStroke, String iconFileName) {
			m_caption = caption;
			m_description = description;
            m_accelerator = keyStroke;
            m_iconFileName = iconFileName;
		}
        
        public ActionProperties(String caption, String description, KeyStroke keyStroke) {
            this(caption,description,keyStroke,null);
        }
        
        
        public ActionProperties(String caption, String description) {
            this(caption,description,null,null);
        }
        
        public ActionProperties(String caption, String description, String iconFileName) {
            this(caption,description,null,iconFileName);
        }
		
		String getCaption() {
			return m_caption;
		}
		
		String getDescription() {
			return m_description;
		}
		
        KeyStroke getAccelerator() {
            return m_accelerator;
        }
        
        String getIconFileName() {
            return m_iconFileName;
        }
        
		private String m_caption;
		private String m_description;
        private KeyStroke m_accelerator;
        public String m_iconFileName;
	}	
	
	public ActionProperties getActionProperties(ActionName name) {
		switch(name) {
        // FILE GROUP
        case FILE_NEW : return new ActionProperties(
                "New",
                "Start a new model",
                KeyStroke.getKeyStroke(KeyEvent.VK_N,InputEvent.META_MASK),
                "filenew.png");
        case FILE_OPEN : return new ActionProperties(
                "Open",
                "Open a model",
                KeyStroke.getKeyStroke(KeyEvent.VK_O,InputEvent.META_MASK),
                "fileopen.png");
        case FILE_SAVE : return new ActionProperties(
                "Save",
                "Save the model",
                KeyStroke.getKeyStroke(KeyEvent.VK_S,InputEvent.META_MASK),
                "filesave.png");
        case FILE_SAVE_AS : return new ActionProperties(
                "Save As...",
                "Save the model with a new filename",
                KeyStroke.getKeyStroke(KeyEvent.VK_S,InputEvent.META_MASK + InputEvent.SHIFT_MASK));
		// QUERY_GROUP
        case QUERY_ADD_TYPES : return new ActionProperties(
                "Create type queries","Add the concept, relation and layer type queries");
		case QUERY_CREATE_SET : return new ActionProperties(
                "Create new set query",
                "Create a new set query from the type query",
                "rubberband.png");
        case QUERY_EXECUTE : return new ActionProperties(
                "Execute",
                "Execute the query in the background. The query node will be "+
                "populated with the results when they become available",
                "play.png");
        case QUERY_CREATE_CUSTOM: return new ActionProperties(
                "Create custom",
                "Create a custom dgbQL query");
        case QUERY_CREATE_FROM_RESULT: return new ActionProperties(
                "Create from result",
                "Create a new query from the selected result items");
        case QUERY_CREATE_NEIGHBOURHOOD: return new ActionProperties(
                "Create neighbourhood",
                "Create a new neighbourhood query from the currently selected query",
                "neighbourhood.png");
        case QUERY_CREATE_CLOSURE: return new ActionProperties(
                "Create closure",
                "Create a new closure query from the currently selected query",
                "closure.png");
                
        // EDIT GROUP
        case EDIT_CUT: return new ActionProperties(
                "Cut",
                "Cut the current query",
                KeyStroke.getKeyStroke(KeyEvent.VK_X,InputEvent.META_MASK),
                "cut.png");
            
        case EDIT_COPY:return new ActionProperties(
                "Copy",
                "Copy the selected queries",
                KeyStroke.getKeyStroke(KeyEvent.VK_C,InputEvent.META_MASK),
                "copy.png");
        case EDIT_PASTE:return new ActionProperties(
                "Paste",
                "Paste the queries on the clipboard",
                KeyStroke.getKeyStroke(KeyEvent.VK_V,InputEvent.META_MASK),
                "paste.png");
        case EDIT_UNDO : return new ActionProperties(
                "Undo",
                "Undo the last action",
                KeyStroke.getKeyStroke(KeyEvent.VK_Z,InputEvent.META_MASK),
                "undo.png");
        case EDIT_REDO : return new ActionProperties(
                "Redo",
                "Redo the last action",
                KeyStroke.getKeyStroke(KeyEvent.VK_Y,InputEvent.META_MASK),
                "redo.png");
        case EDIT_DELETE: return new ActionProperties(
                "Delete",
                "Delete the selected node(s)",
                KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0),
                "cross.png");
        case EDIT_RENAME : return new ActionProperties(
                "Rename",
                "Rename a query node",
                KeyStroke.getKeyStroke(KeyEvent.VK_F2,0));
        case EDIT_MODIFY : return new ActionProperties(
                "Properties",
                "Edit the properties of a query node");
		// BOOLEAN GROUP
		case BOOLEAN_INTERSECT : return new ActionProperties(
                "Intersect",
                "Create an intersection between query nodes",
                "intersect.png");
		case BOOLEAN_UNION : return new ActionProperties(
                "Union",
                "Create a union between query nodes",
                "union.png");
		case BOOLEAN_NOT : return new ActionProperties(
                "NOT",
                "Create a differerence between query nodes",
                "diff.png");
        case BOOLEAN_XOR : return new ActionProperties(
                "XOR",
                "Create a XOR between query nodes",
                "xor.png");
		// Application group
        case DGB_SETTINGS : return new ActionProperties(
                "Settings","DGB connection settings");
        case DGB_GET_IOR_VIA_HTTP: return new ActionProperties(
                "Update connection settings","Update the connection setting over the internet");
        // Perspectives group
        case PERSPECTIVE_DEFAULT : return new ActionProperties(
                "Default","The default full-functionality perspective");
        case PERSPECTIVE_MODEL : return new ActionProperties(
                "Model","The model-driven perspective");
		// MODEL_DRIVEN
        case MODEL_SET_TARGET: return new ActionProperties(
                "Set Target","Set the target of the model-driven interface",
                "magnifying.png");
        }
        
		// Nothing else is allowed
		assert false;
		return new ActionProperties("Default","Default");
	}

    /**
     * The Action groups. Note that this order is also the order in which they appear 
     * on the menu bar
     * @author bjnortier
     *
     */
	public static enum ActionGroupName {
        FILE,
        EDIT,
        QUERY,
		BOOLEAN,
        MODELDRIVEN,
		TEST,
        DGB,
        PERSPECTIVE
	}
	
	private String getGroupName(ActionGroupName name) {
		switch(name) {
        case FILE : return "File";
		case QUERY :return "Query";
        case EDIT : return "Edit";
		case TEST :return "Test";
		case BOOLEAN : return "Boolean";
        case MODELDRIVEN : return "Model";
        case DGB : return "DGB";
        case PERSPECTIVE: return "Perspective";
		default: assert false;
		}
		return "";
	}
	
    // Private for singleton
	private ActionRepository() {
		m_actionMap = new EnumMap<ActionName,AbstractAction>(ActionName.class);
		m_actionGroupMap = new EnumMap<ActionGroupName,ActionGroup>(ActionGroupName.class);
	}
	
	public void initAllActions() {
		ActionGroup group;
        // FILE GROUP
        group = new ActionGroup(getGroupName(ActionGroupName.FILE));
        group.add(getAction(ActionName.FILE_NEW));
        group.add(getAction(ActionName.FILE_OPEN));
        group.add(getAction(ActionName.FILE_SAVE));
        group.add(getAction(ActionName.FILE_SAVE_AS));
        m_actionGroupMap.put(ActionGroupName.FILE, group);
        // EDIT GROUP
        group = new ActionGroup(getGroupName(ActionGroupName.EDIT));
        
        group.add(getAction(ActionName.EDIT_UNDO));
        group.add(getAction(ActionName.EDIT_REDO));
        group.add(getAction(ActionName.EDIT_CUT));
        group.add(getAction(ActionName.EDIT_COPY));
        group.add(getAction(ActionName.EDIT_PASTE));
        group.add(getAction(ActionName.EDIT_DELETE));
        group.add(getAction(ActionName.EDIT_RENAME));
        group.add(getAction(ActionName.EDIT_MODIFY));
        m_actionGroupMap.put(ActionGroupName.EDIT, group);
		// QUERY_GROUP
		group = new ActionGroup(getGroupName(ActionGroupName.QUERY));
        group.add(getAction(ActionName.QUERY_ADD_TYPES));
        group.add(getAction(ActionName.QUERY_CREATE_SET));
        //group.add(getAction(ActionName.QUERY_CREATE_PATH));
        group.add(getAction(ActionName.QUERY_EXECUTE));
        group.add(getAction(ActionName.QUERY_CREATE_CUSTOM));
        group.add(getAction(ActionName.QUERY_CREATE_FROM_RESULT));
        group.add(getAction(ActionName.QUERY_CREATE_NEIGHBOURHOOD));
        group.add(getAction(ActionName.QUERY_CREATE_CLOSURE));
		m_actionGroupMap.put(ActionGroupName.QUERY, group);
		// BOOLEAN_GROUP
		group = new ActionGroup(getGroupName(ActionGroupName.BOOLEAN));
		group.add(getAction(ActionName.BOOLEAN_UNION));
		group.add(getAction(ActionName.BOOLEAN_INTERSECT));
		group.add(getAction(ActionName.BOOLEAN_NOT));
        group.add(getAction(ActionName.BOOLEAN_XOR));
		m_actionGroupMap.put(ActionGroupName.BOOLEAN, group);	
        // APP_GROUP
        group = new ActionGroup(getGroupName(ActionGroupName.DGB));
        group.add(getAction(ActionName.DGB_SETTINGS));
        group.add(getAction(ActionName.DGB_GET_IOR_VIA_HTTP));
        m_actionGroupMap.put(ActionGroupName.DGB, group);  
        // PERSPECTIVE group
        group = new ActionGroup(getGroupName(ActionGroupName.PERSPECTIVE));
        group.add(getAction(ActionName.PERSPECTIVE_DEFAULT));
        group.add(getAction(ActionName.PERSPECTIVE_MODEL));
        m_actionGroupMap.put(ActionGroupName.PERSPECTIVE, group);
        // MODEL_DRIVEN GROUP
        group = new ActionGroup(getGroupName(ActionGroupName.MODELDRIVEN));
        group.add(getAction(ActionName.MODEL_SET_TARGET));
        m_actionGroupMap.put(ActionGroupName.MODELDRIVEN, group);
        
		
	}
	
	public AbstractAction getAction(ActionName name) {
		AbstractAction action = getInstance().m_actionMap.get(name);
		if (action == null) {
			// Get the action parameters
			ActionProperties properties = getInstance().getActionProperties(name);
			// Create the action and add it to the map
			action = ActionFactory.createAction(name,properties);
			getInstance().m_actionMap.put(name,action);
		}
		assert (action != null);
		return action;
	}
	
	public ActionGroup getActionGroup(ActionGroupName name) {
		// No on-the-fly creation allowed for groups
		assert (m_actionGroupMap.get(name) != null);
		return m_actionGroupMap.get(name);
	}
	
	public Set<ActionGroupName> getAllActionGroupNames() {
		return m_actionGroupMap.keySet();
	}

	public static ActionRepository getInstance() {
		if (m_actionRepository == null) {
			m_actionRepository = new ActionRepository();
		}
		return m_actionRepository;
	}
    
    
    
    public Set<ActionGroup> getModelDrivenToolbarGroups() {
        Set<ActionGroup> toolBarGroups = new LinkedHashSet<ActionGroup>();
        
        ActionGroup toolBarGroup;
        
        // The File toolbar
        toolBarGroup = new ActionGroup("File");
        toolBarGroup.add(getAction(ActionName.FILE_NEW));
        toolBarGroup.add(getAction(ActionName.FILE_OPEN));
        toolBarGroup.add(getAction(ActionName.FILE_SAVE));
        toolBarGroups.add(toolBarGroup);
        
        // The Edit Toolbar
        toolBarGroup = new ActionGroup("Edit");
        toolBarGroup.add(getAction(ActionName.EDIT_CUT));
        toolBarGroup.add(getAction(ActionName.EDIT_COPY));
        toolBarGroup.add(getAction(ActionName.EDIT_PASTE));
        toolBarGroup.add(getAction(ActionName.EDIT_DELETE));
        toolBarGroup.add(getAction(ActionName.EDIT_UNDO));
        toolBarGroup.add(getAction(ActionName.EDIT_REDO));
        toolBarGroups.add(toolBarGroup);
        
        // The model-driven toolbar
        toolBarGroup = new ActionGroup("ModelDriven");
        toolBarGroup.add(getAction(ActionName.MODEL_SET_TARGET));
        toolBarGroups.add(toolBarGroup);
        
        return toolBarGroups;
    }
    
	public Set<ActionGroup> getDefaultToolbarGroups() {
        
        Set<ActionGroup> toolBarGroups = new LinkedHashSet<ActionGroup>();
        
        ActionGroup toolBarGroup;
        
        // The File toolbar
        toolBarGroup = new ActionGroup("File");
        toolBarGroup.add(getAction(ActionName.FILE_NEW));
        toolBarGroup.add(getAction(ActionName.FILE_OPEN));
        toolBarGroup.add(getAction(ActionName.FILE_SAVE));
        toolBarGroups.add(toolBarGroup);
        
        // The Edit Toolbar
        toolBarGroup = new ActionGroup("Edit");
        toolBarGroup.add(getAction(ActionName.EDIT_CUT));
        toolBarGroup.add(getAction(ActionName.EDIT_COPY));
        toolBarGroup.add(getAction(ActionName.EDIT_PASTE));
        toolBarGroup.add(getAction(ActionName.EDIT_DELETE));
        toolBarGroup.add(getAction(ActionName.EDIT_UNDO));
        toolBarGroup.add(getAction(ActionName.EDIT_REDO));
        toolBarGroups.add(toolBarGroup);
        
        // The Boolean Toolbar
        toolBarGroup = new ActionGroup("Boolean");
        toolBarGroup.add(getAction(ActionName.BOOLEAN_UNION));
        toolBarGroup.add(getAction(ActionName.BOOLEAN_INTERSECT));
        toolBarGroup.add(getAction(ActionName.BOOLEAN_NOT));
        toolBarGroup.add(getAction(ActionName.BOOLEAN_XOR));
        toolBarGroups.add(toolBarGroup);
        
        // The query toolbar
        toolBarGroup = new ActionGroup("Query");
        toolBarGroup.add(getAction(ActionName.QUERY_CREATE_SET));
        toolBarGroup.add(getAction(ActionName.QUERY_CREATE_NEIGHBOURHOOD));
        toolBarGroup.add(getAction(ActionName.QUERY_CREATE_CLOSURE));
        toolBarGroup.add(getAction(ActionName.QUERY_EXECUTE));
        toolBarGroups.add(toolBarGroup);
        

        
        return toolBarGroups;
    }

	// The action lookup map
	private Map<ActionName,AbstractAction> m_actionMap;
	// The action group lookup map
	private Map<ActionGroupName,ActionGroup> m_actionGroupMap;
	// Singleton instance
	private static ActionRepository m_actionRepository;
	
}
